class Func
	attr_reader :args, :name
	
	def initialize
		@args = Array.new
	end
	
	def push x
		@args.push x
	end
	
	def to_s
		s = @name
		@args.each do |i|
			s += "(#{i.to_s})"
		end
		s
	end
	
	def to_i
		raise 'Attempt to convert non-zero to integer ' + @name
	end

	def check_slot_number i
		raise "Invalid slot number: "  if !0..255.include?(i.to_i)
	end

	def check_slot i
		check_slot_number i
		raise "Slot " + i + " is dead" if $my_slots[i.to_i].vitality <= 0
	end

	def check_apply_nesting
		$application_num+=1
		if $application_num > 1000
			raise '>1000 applications'
		end
	end

end

class Zero < Func
	def initialize
		super
		@name = "zero"
	end
	
	def apply x
		raise 'Zero cannot be applied'
	end
 
	def succ
		1
	end
	
	def to_i
		0
	end

end

class I < Func
	def initialize
		super
		@name = "I"
	end
	def apply x
		check_apply_nesting
		x
	end
end

class K < Func
	def initialize
		super
		@name = "K"
	end
	def apply x
		check_apply_nesting
		if @args.size == 1
				@args[0]
		elsif @args.size > 1
			raise 'K cant have >2 args'
		else
			push x
			self
		end
	end  
end

class S < Func
	def initialize
		super
		@name = "S"
	end
	def apply x
		check_apply_nesting
		case @args.size 
			when 3
				raise 'S cant have >3 args'
			when 2
				f = @args[0]
				g = @args[1]
				h = f.apply x
				y = g.apply x
				h.apply y
			when 0,1
				push x
				self
		end
	end
end

class Succ < Func
	def initialize
		super
		@name = "succ"
	end
	def apply n
		check_apply_nesting
		i = n.to_i
		i += 1
		i = i > 65535 ? 65535 : i
		i
	end
end

class Dbl < Func
	def initialize
		super
		@name = "dbl"
	end
	def apply n
		check_apply_nesting
		n = n.to_i() *2
		n  = n > 65535 ? 65535 : n
		n
	end
end

class Get < Func
	def initialize
		super
		@name = "get"
	end
	def apply i
		check_apply_nesting
		check_slot i
		$my_slots[i.to_i].field

	end
end

class Put < Func
	def initialize
		super
		@name = "put"
	end
	def apply i
		check_apply_nesting
		I.new
	end
end

class Inc < Func
	def initialize
		super
		@name = "inc"
	end
	def apply i
		check_apply_nesting
		check_slot_number i
		$my_slots[i.to_i].vitality += 1 if i.to_i > 0 && i.to_i <65535
		I.new
	end
end

class Dec < Func
	def initialize
		super
		@name = "dec"
	end
	def apply i
		check_apply_nesting
		check_slot_number i
		$enemy_slots[i.to_i].vitality -= 1 if i.to_i > 0 && i.to_i <65535
		I.new
	end
end

class Attack < Func
  def initialize
    super
    @name = "attack"
  end
  def apply x
    check_apply_nesting
    case @args.size
      when 0, 1
        push x
        self
      when 2
        i = @args[0].to_i
        j = @args[1].to_i
        n = x.to_i
        check_slot_number i
        check_slot_number j
        
        v = $my_slots[i].vitality
        raise "Not enough vitality (" + v +") for an atack (" + n +")" if n.to_i > v
        
        $my_slots[i].vitality -= n.to_i
        $enemy_slots[255 - j].vitality -= n.to_i * 9 / 10
        $enemy_slots[255 - j].vitality = 0 if $enemy_slots[255 - j].vitality < 1

				I.new
		end
	end
end

class Help < Func
  def initialize
    super
    @name = "help"
  end
  def apply x
    check_apply_nesting
    case @args.size
      when 0, 1
        push x
        self
      when 2
        #puts @args[2]
        
        i = @args[0].to_i
        j = @args[1].to_i
        n = x
        check_slot_number i
        check_slot_number j
        
        #puts "help #{i}, #{j}, #{n}"
        
        v = $my_slots[i].vitality
        raise "Not enough vitality (#{v}) for an help (#{n})" if n.to_i >= v
        
        $my_slots[i].vitality -= n.to_i
        $my_slots[j].vitality += n.to_i * 11 / 10
        $my_slots[j].vitality = 65535 if $my_slots[j].vitality > 65535
        
        I.new
    end
  end
end

class Copy < Func
	def initialize
		super
		@name = "copy"
	end
	def apply i
		check_apply_nesting
		check_slot_number i
		$enemy_slots[i.to_i].field
	end
end

class Revive < Func
	def initialize
		super
		@name = "revive"
	end
	def apply i
		check_apply_nesting
		check_slot_number i
		$my_slots[i.to_i].vitality = 1 if $my_slots[i.to_i].vitality <= 0
		I.new
	end
end

class Zombie < Func
  def initialize
    super
    @name = "zombie"
  end
  def apply x
    check_apply_nesting
    case @args.size
      when 0
        push x
        self
      when 1
        i = @args[0].to_i
        check_slot_number i
        #raise "Slot " + i.to_s + " is alive" if $enemy_slots[255 - i].vitality > 0
        #p x
        
        $enemy_slots[255 - i].field = x
        $enemy_slots[255 - i].vitality = -1
        I.new
    end
  end
end